//
//  Service.m
//  ShopInMall_OC
//
//  Created by Sailer Guo on 2019/10/11.
//  Copyright © 2019 Sailer Guo. All rights reserved.
//

#import "HTTPService.h"
#import <AFNetworking/AFNetworking.h>
#import "CenterServiceConfig.h"
#import "SPIntelligentServiceConfig.h"
#import "SPCMSService.h"
#import "AppInfoModel.h"
#import <MJExtension/MJExtension.h>

NSErrorDomain const NSErrorDomainNoAdaptiveData = @"NSErrorDomainSPServiceNoAdaptiveData";
NSErrorCode const NSSPErrorCode = 1004;

@interface HTTPService ()

@property (nonatomic,strong) NSMutableDictionary *serviceCollection;

@end

@implementation HTTPService

#pragma mark - 网络请求的方法，返回一个包含请求数据的信号
- (RACSignal *)signalProduce:(RACTuple *)router withDecodeClass:(Class)cls isList:(BOOL)isList {

    // 这里通过请求router的service 类型，取出它的session，去对应的服务获取数据
    id <ServiceConfig> serviceConfig = [self.serviceCollection objectForKey:router.fourth];

    NSURLRequest *request = [self prepareReqeustWithTuple:router session:serviceConfig.session];
    
    NSMutableSet *contentTypes = serviceConfig.session.responseSerializer.acceptableContentTypes.mutableCopy;
    
    if ([request.URL.absoluteString hasSuffix:@"html"]) {
        [contentTypes addObject:@"text/html"];
    }else{
        [contentTypes addObject:@"text/plain"];
    }
    
    serviceConfig.session.responseSerializer.acceptableContentTypes = contentTypes;
    
    RACSignal *remoteSignal = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
            
            NSURLSessionDataTask *task = [serviceConfig.session dataTaskWithRequest:request uploadProgress:nil downloadProgress:nil completionHandler:^(NSURLResponse * _Nonnull response, id  _Nullable responseObject, NSError * _Nullable error) {
                
                if (error) {
                    
                    [self.errors sendError:error];
                    [subscriber sendError:error];
                    
                } else {
                    
                    // 不同的service其返回的格式可能不同，可以把解析的工作放在serviceConfig中，有针对性的处理
                    if ([serviceConfig successWitResponseObject:responseObject]) {
                        id data = [serviceConfig responseData:responseObject withUrl:router.second isList:isList];
                        
    #ifdef DEBUG
                        NSLog(@"%@ response >>> %@",router.second,responseObject);
    #endif
                        [subscriber sendNext:data];
                        [subscriber sendCompleted];
                    } else {
                        
    #ifdef DEBUG
                        NSLog(@"%@ error >>> %@",router.second,error.userInfo);
    #endif
                        [subscriber sendError:error];
                    }
                }
            }];
            
            [task resume];
            
            return [RACDisposable disposableWithBlock:^{
                [task cancel];
            }];
    }];
    
    // 如果没有传入需要解析的类型，直接把结果透传到页面
    if (cls) {
       return [remoteSignal flattenMap:^__kindof RACSignal * _Nullable(id  _Nullable value) {
           
           return [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
               id result;
               
               if (isList) {
                   // 返回的是列表格式的数据
                   result = [cls mj_objectArrayWithKeyValuesArray:value];
               } else {
                   // 返回对象类型的数据
                   result = [cls mj_objectWithKeyValues:value];
               }
               
               if (!result) {
                   [subscriber sendError:[NSError mj_error]];
               } else {
                   [subscriber sendNext:result];
                   [subscriber sendCompleted];
               }
               
               return [RACDisposable disposableWithBlock:^{
                   
               }];
           }];
       }];
    }
    
    return remoteSignal;
}

- (RACSignal *)uploadFileSignal:(RACTuple *)router {
    
    // 这里通过请求router的service 类型，取出它的session，去对应的服务获取数据
    id <ServiceConfig> serviceConfig = [self.serviceCollection objectForKey:router.fourth];

    NSString *url = (NSString *)router.second;
    url = [serviceConfig.baseUrl stringByAppendingString:url];

    return [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
        
        [serviceConfig.session POST:url parameters:@{} constructingBodyWithBlock:^(id<AFMultipartFormData>  _Nonnull formData) {
            
            NSData *data = router.third[@"uploadFile"];
            [formData appendPartWithFileData:data name:@"uploadFile" fileName:@"photoFile.png" mimeType:@"multipart/form-data"];
            
        } progress:^(NSProgress * _Nonnull uploadProgress) {
            
        } success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
            NSDictionary *data = responseObject[@"data"];
            [subscriber sendNext:data];
            [subscriber sendCompleted];

        } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
            [subscriber sendError:error];
        }];
        
        return [RACDisposable disposableWithBlock:^{
            
        }];
    }];
}

- (id<ServiceConfig>)getServiceConfigFor:(HTTPServiceType)serviceType {
    return [self.serviceCollection objectForKey:@(serviceType)];
}

#pragma mark - Private
- (NSURLRequest *)prepareReqeustWithTuple:(RACTuple *)tuple session:(AFHTTPSessionManager *)session {
    NSString *httpMethod = [self httpMethod:tuple.first];
    NSString *url = (NSString *)tuple.second;
    NSDictionary *parameters = tuple.third;
    [self configPublicParameters:parameters];
    NSMutableURLRequest *request = [session.requestSerializer requestWithMethod:httpMethod URLString:[[NSURL URLWithString:url relativeToURL:session.baseURL] absoluteString] parameters:parameters error:nil];
    
    return request;
}

- (NSDictionary *)configPublicParameters:(NSDictionary *)parameters {
    AppInfoModel *appInfoDTO  = [AppInfoModel sharedInstance];
    NSMutableDictionary *necessaryParameters = [NSMutableDictionary dictionaryWithCapacity:0];
    [necessaryParameters setObject:[NSString stringWithFormat:@"%@",appInfoDTO.deviceType] forKey:@"deviceType"];
    [necessaryParameters setObject:[NSString stringWithFormat:@"%@",appInfoDTO.deviceSn] forKey:@"deviceSn"];
    [necessaryParameters setObject:[NSString stringWithFormat:@"%@",appInfoDTO.appVersion] forKey:@"appVersion"];
    [necessaryParameters setObject:[NSString stringWithFormat:@"%@",appInfoDTO.systemVersion] forKey:@"systemVersion"];
    [necessaryParameters setObject:[NSString stringWithFormat:@"%@",appInfoDTO.versionNo] forKey:@"versionNo"];
    [necessaryParameters setObject:[NSString stringWithFormat:@"%@",appInfoDTO.os] forKey:@"os"];
    [necessaryParameters addEntriesFromDictionary:parameters];
    return necessaryParameters;
}

- (NSString *)httpMethod:(NSNumber *)type {
    NSDictionary *dict = @{
        @(POST):@"POST",
        @(GET):@"GET"
    };
    return dict[type];
}

- (void)switchEnv:(EnvironmentType)env {
    [self.serviceCollection removeAllObjects];
        
    // center service
    id<ServiceConfig> _Nonnull centerService = [CenterServiceConfig serviceConfigWith:env];
    [self.serviceCollection addEntriesFromDictionary:@{@(HTTPServiceTypeCenter):centerService}];
    
    // 达人
    id<ServiceConfig> _Nonnull intelligentService = [SPIntelligentServiceConfig serviceConfigWith:env];
    [self.serviceCollection addEntriesFromDictionary:@{@(HTTPServiceTypeIntelligent):intelligentService}];

}

- (BOOL)didParameters:(NSDictionary *)parameters containNecessaryKeys:(NSArray *)necessaryKeys {
    if (parameters.count == 0 || necessaryKeys.count == 0) {
        return YES;
    }
    NSSet *paramKeys = [NSSet setWithArray:parameters.allKeys];
    return [[NSSet setWithArray:necessaryKeys] isSubsetOfSet:paramKeys];
}

#pragma mark - Getters
- (NSMutableDictionary *)serviceCollection {
    if (!_serviceCollection) {
        _serviceCollection = @{}.mutableCopy;
    }
    return _serviceCollection;
}

- (RACSubject *)errors {
    if (!_errors) {
        _errors = [RACSubject subject];
    }
    return _errors;
}

@end
